package top.haijunit.work.modules.access.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.haijunit.work.core.doamin.ExceptionServer;
import top.haijunit.work.modules.access.domain.AssignRole;
import top.haijunit.work.modules.access.entity.RoleEntity;
import top.haijunit.work.modules.access.entity.SubjectPermissionEntity;
import top.haijunit.work.modules.access.mapper.SubjectPermissionMapper;
import top.haijunit.work.modules.core.Resource;
import top.haijunit.work.modules.core.Subject;
import top.haijunit.work.utils.StreamUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zhanghaijun
 * @description 针对表【access_ENTITY_PERMISSION(授权权限表)】的数据库操作Service实现
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SubjectPermissionService {

    private final SubjectPermissionMapper baseMapper;
    private final RoleService roleService;
    private final PermissionService permissionService;

    /**
     * 获取主体角色
     */
    @Deprecated
    public List<RoleEntity> getRole(Subject subject) {
        LambdaQueryWrapper<SubjectPermissionEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubjectPermissionEntity::getEntityType, subject.getSubjectType());
        queryWrapper.eq(SubjectPermissionEntity::getEntityCode, subject.getSubjectCode());
        List<SubjectPermissionEntity> list = baseMapper.selectList(queryWrapper);
        Set<Long> roleCodeList = list.stream().map(SubjectPermissionEntity::getRoleCode).collect(Collectors.toSet());
        // 查询role
        LambdaQueryWrapper<RoleEntity> roleQueryWrapper = new LambdaQueryWrapper<>();
        roleQueryWrapper.in(RoleEntity::getUniqCode, roleCodeList);
        return roleService.list(roleQueryWrapper);
    }

    /**
     * 获取主体授权权限
     */
    public Map<Long, Integer> getPermission(Subject subject, Resource resource) {
        LambdaQueryWrapper<SubjectPermissionEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubjectPermissionEntity::getEntityType, subject.getSubjectType());
        queryWrapper.eq(SubjectPermissionEntity::getEntityCode, subject.getSubjectCode());
        queryWrapper.eq(SubjectPermissionEntity::getResourceKey, resource.getResourceCode());
        List<SubjectPermissionEntity> entityList = baseMapper.selectList(queryWrapper);
        // 获取角色code
        List<Long> roleCodes = StreamUtils.mapToList(entityList, SubjectPermissionEntity::getRoleCode);
        return roleService.getRolePermissionMap(roleCodes);
    }

    /**
     * 主体是否有权限
     */
    public boolean hasPermission(Subject subject, Resource resource, Long... permissionCode) {
        Map<Long, Integer> permissionMap = getPermission(subject, resource);
        for (Long code : permissionCode) {
            if (!permissionMap.containsKey(code) || permissionMap.get(code) != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 给主体分配角色
     */
    public void assignRoleToSubject(AssignRole assignRole) {
        // 主体的有效性校验 待加
        // 资源的有效性校验 待加
        LambdaQueryWrapper<SubjectPermissionEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubjectPermissionEntity::getEntityType, assignRole.getSubjectType());
        queryWrapper.eq(SubjectPermissionEntity::getEntityCode, assignRole.getSubjectCode());
        queryWrapper.eq(SubjectPermissionEntity::getRoleCode, assignRole.getRoleCode());
        queryWrapper.eq(SubjectPermissionEntity::getResourceKey, assignRole.getResourceCode());
        if (CollUtil.isNotEmpty(baseMapper.selectList(queryWrapper))) {
            throw new ExceptionServer("角色已分配，请勿重复分配");
        }
        // 检查角色权限是否存在冲突，（在创建角色已检查，冗余再检查一边，后续观察性能执行情况再定是否去掉该项检查）
        Map<Long, Integer> rolePermissionMap = roleService.getRolePermissionMap(Collections.singletonList(assignRole.getRoleCode()));
        permissionService.checkPermissionConflicts(rolePermissionMap.keySet());
        // 检查角色权限和已分配的权限是否存在冲突
        //Map<String, Integer> permissionMap = getPermission(subject, resource);
        //permissionService.checkPermissionListExclusion(rolePermissionMap.keySet(), permissionMap.keySet());
        // 分配权限保存
        SubjectPermissionEntity entity = new SubjectPermissionEntity();
        entity.setEntityType(assignRole.getSubjectType());
        entity.setEntityCode(assignRole.getSubjectCode());
        entity.setResourceKey(assignRole.getResourceCode());
        entity.setRoleCode(assignRole.getRoleCode());
        baseMapper.insert(entity);
    }

    /**
     * 移除主体角色，all
     */
    public void removeRoleFromSubject(Subject subject) {
        LambdaQueryWrapper<SubjectPermissionEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubjectPermissionEntity::getEntityType, subject.getSubjectType());
        queryWrapper.eq(SubjectPermissionEntity::getEntityCode, subject.getSubjectCode());
        baseMapper.delete(queryWrapper);
    }

    /**
     * 移除主体角色，针对资源
     */
    public void removeRoleFromSubject(Subject subject, Resource resource) {
        LambdaQueryWrapper<SubjectPermissionEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubjectPermissionEntity::getEntityType, subject.getSubjectType());
        queryWrapper.eq(SubjectPermissionEntity::getEntityCode, subject.getSubjectCode());
        queryWrapper.eq(SubjectPermissionEntity::getResourceKey, resource.getResourceCode());
        baseMapper.delete(queryWrapper);
    }

    /**
     * 移除主体角色，针对资源+角色
     */
    public void removeRoleFromSubject(Subject subject, Resource resource, String roleCode) {
        LambdaQueryWrapper<SubjectPermissionEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubjectPermissionEntity::getEntityType, subject.getSubjectType());
        queryWrapper.eq(SubjectPermissionEntity::getEntityCode, subject.getSubjectCode());
        queryWrapper.eq(SubjectPermissionEntity::getResourceKey, resource.getResourceCode());
        queryWrapper.eq(SubjectPermissionEntity::getRoleCode, roleCode);
        baseMapper.delete(queryWrapper);
    }
}




